﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace WPFSample.CircleTheButtonsSample
{
    public enum RadialPanelOrientation
    {
        ByWidth,
        ByHeight
    }

    class RadialPanel : Panel
    {
        double angleEach;
        Size sizeLargest;
        double radius;
        double outerEdgeFromCenter;
        double innerEdgeFromCenter;

        private bool showPieLines;

        public bool ShowPieLines
        {
            get
            {
                return this.showPieLines;
            }

            set
            {
                if (value != this.showPieLines)
                {
                    this.InvalidateArrange();
                }

                showPieLines = value;
            }
        }

        public RadialPanelOrientation Orientation
        {
            get { return (RadialPanelOrientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Orientation.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(RadialPanelOrientation), typeof(RadialPanel), new FrameworkPropertyMetadata(RadialPanelOrientation.ByWidth, FrameworkPropertyMetadataOptions.AffectsMeasure));

        protected override Size MeasureOverride(Size availableSize)
        {
            if (this.InternalChildren.Count == 0)
            {
                return new Size(0, 0);
            }

            this.angleEach = 360.0 / this.InternalChildren.Count;
            this.sizeLargest = new Size(0, 0);

            foreach (UIElement child in this.InternalChildren)
            {
                child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
                this.sizeLargest.Width = Math.Max(this.sizeLargest.Width, child.DesiredSize.Width);
                this.sizeLargest.Height = Math.Max(this.sizeLargest.Height, child.DesiredSize.Height);
            }

            if (this.Orientation == RadialPanelOrientation.ByWidth)
            {
                this.innerEdgeFromCenter = this.sizeLargest.Width / 2 / Math.Tan(Math.PI * this.angleEach / 180 / 2);
                this.outerEdgeFromCenter = this.innerEdgeFromCenter + this.sizeLargest.Height;
                this.radius = Math.Sqrt(Math.Pow(this.sizeLargest.Width / 2, 2) + Math.Pow(this.outerEdgeFromCenter, 2));
            }
            else
            {
                this.innerEdgeFromCenter = this.sizeLargest.Height / 2 / Math.Tan(Math.PI * this.angleEach / 360);
                this.outerEdgeFromCenter = this.innerEdgeFromCenter + this.sizeLargest.Width;
                this.radius = Math.Sqrt(Math.Pow(this.sizeLargest.Height / 2, 2) + Math.Pow(this.outerEdgeFromCenter, 2));
            }

            return new Size(2 * this.radius, 2 * this.radius);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            double angleChild = 0;
            Point ptCenter = new Point(finalSize.Width / 2, finalSize.Height / 2);
            double multiplier = Math.Min(finalSize.Width / (2 * this.radius), finalSize.Height / (2 * this.radius));
            foreach (UIElement child in this.InternalChildren)
            {
                child.RenderTransform = Transform.Identity;
                if (this.Orientation == RadialPanelOrientation.ByWidth)
                {
                    child.Arrange(new Rect(ptCenter.X - multiplier * this.sizeLargest.Width / 2,
                        ptCenter.Y - multiplier * this.outerEdgeFromCenter,
                        multiplier * this.sizeLargest.Width,
                        multiplier * this.sizeLargest.Height));
                }
                else
                {
                    child.Arrange(new Rect(ptCenter.X + multiplier * this.innerEdgeFromCenter,
                        ptCenter.Y - multiplier * this.sizeLargest.Height / 2,
                        multiplier * this.sizeLargest.Width,
                        multiplier * this.sizeLargest.Height));
                }

                Point pt = TranslatePoint(ptCenter, child);
                child.RenderTransform = new RotateTransform(angleChild, pt.X, pt.Y);
                angleChild += this.angleEach;
            }

            return finalSize;
        }

        protected override void OnRender(DrawingContext dc)
        {
            base.OnRender(dc);
            if (this.ShowPieLines)
            {
                Point ptCenter = new Point(this.RenderSize.Width / 2, this.RenderSize.Height / 2);
                double multiplier = Math.Min(this.RenderSize.Width / (2 * this.radius), this.RenderSize.Height / (2 * this.radius));
                Pen pen = new Pen(SystemColors.WindowTextBrush, 1);
                pen.DashStyle = DashStyles.Dash;

                dc.DrawEllipse(null, pen, ptCenter, multiplier * this.radius, multiplier * this.radius);

                double angleChild = -this.angleEach / 2;
                if (this.Orientation == RadialPanelOrientation.ByWidth)
                {
                    angleChild += 90;
                }

                foreach (UIElement child in this.InternalChildren)
                {
                    dc.DrawLine(
                        pen,
                        ptCenter,
                        new Point(
                            ptCenter.X + multiplier * this.radius * Math.Cos(2 * Math.PI * angleChild / 360),
                            ptCenter.Y + multiplier * this.radius * Math.Sin(2 * Math.PI * angleChild / 360)));
                    angleChild += this.angleEach;
                }
            }
        }
    }
}
